#include "comLogManager.h"
#include "InfoCollectMgr.h"
#include "ttcodeStateChart.h"



#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>


#include <wx/process.h>



InfoCollectMgr::InfoCollectMgr()
:wxThread()
,m_server(NULL)
,m_RecievSize(0)
,m_Run(true)
,m_Mutex()
,m_Cond(m_Mutex)
,m_ShowCouter(0)
{
	this->Create();
	this->Run();
}

void InfoCollectMgr::OnServerEvent(wxSocketEvent& evt)
{
	switch(evt.GetSocketEvent())
	{
	case wxSOCKET_CONNECTION : 
		break;
    default :
		return;
	}
	wxSocketBase *sock = m_server->Accept(false);
	if ( NULL == sock )
	{
		return ;
	}
	sock->SetEventHandler(*this, wxID_Socket);
	sock->SetNotify( wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG );
	sock->Notify(true);
}


void InfoCollectMgr::OnSocketEvent(wxSocketEvent& evt)
{
	wxSocketBase *sock = evt.GetSocket();
	if ( NULL == sock )
	{
		return ;
	}
	switch(evt.GetSocketEvent())
	{
	case wxSOCKET_INPUT :
		{
			char buff[1024 * 4];
			memset(buff,0x0,sizeof(buff));
			sock->Read(buff,sizeof(buff));
			ttcode_log << "wxSOCKET_INPUT buff=<" << buff << ">" << endl;
			wxUint32 ioSize = sock->GetLastIOSize();
			m_RecievSize += ioSize;
//			ttcode_log << "wxSOCKET_INPUT ioSize=<" << ioSize << ">" << endl;
			this->recievReport(string(buff));
			break;
		}
 	case wxSOCKET_LOST : 
		{
//			ttcode_log << " wxSOCKET_LOST " << endl;
			sock->Destroy();
			break;
		}
   default :
		return;
	}
}

BEGIN_EVENT_TABLE(InfoCollectMgr, wxEvtHandler)
  EVT_SOCKET(wxID_Server,  InfoCollectMgr::OnServerEvent)
  EVT_SOCKET(wxID_Socket,  InfoCollectMgr::OnSocketEvent)
END_EVENT_TABLE()



unsigned short InfoCollectMgr::startListen(void)
{
//	wxSocketServer *m_server;
#if wxUSE_IPV6
	wxIPV6address addr;
#else
	wxIPV4address addr;
#endif
	srand( time(0) );
	unsigned short ret =  50000 + ( rand() % 3000 );
	addr.Service(ret);
	m_server = new wxSocketServer(addr);
	m_server->SetEventHandler(*this, wxID_Server);
	m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
	m_server->Notify(true);
	return ret;
}

void *InfoCollectMgr::Entry()
{
	ttcode_log << endl;
	while( m_Run )
	{
		wxMutexLocker lock(m_Mutex);
		if( m_BuildInfo.empty() )
		{
			m_Cond.Wait();
		}
		BOOST_FOREACH(string item,m_BuildInfo)
		{
			boost::smatch what;
			if( boost::regex_search(item,what, boost::regex("<ActStart>(.*)</ActStart>")) )
			{
//				ttcode_log << "string(what[0])=<" << string(what[0]) << ">" << endl;
				this->parseReportAction(string(what[0]));
			}
			if( boost::regex_search(item,what, boost::regex("<Result>(.*)</Result>")) )
			{
				this->parseReportResult(string(what[0]));
			}
			if( boost::regex_search(item,what, boost::regex("ttbuild finish")) )
			{
				this->m_ViewInfo.push_back(item);
			}
		}
		m_BuildInfo.clear();
	}
	return NULL;
}





void InfoCollectMgr::getTopReport( ReportInfoList & report )
{
	report.clear();
	wxMutexError err = m_Mutex.TryLock();
	if( wxMUTEX_NO_ERROR == err )
	{
		const int reportCounter = this->m_ViewInfo.size(); 
		while ( reportCounter > m_ShowCouter )
		{
			report.push_back(this->m_ViewInfo[m_ShowCouter++]);
		}
		m_Mutex.Unlock();
	}
}


void InfoCollectMgr::recievReport(const string &report)
{
	wxMutexLocker lock(m_Mutex);
	m_BuildInfo.push_back(report);
	m_Cond.Signal();
}
void InfoCollectMgr::parseReportAction(const string &cmd)
{
	boost::smatch what;
	string content(">");
	bool output = false;
	if( boost::regex_search(cmd,what, boost::regex("<act>(.*)</act>")) )
	{
		string text(what[0]);
		if( boost::regex_search(text,what, boost::regex("bc_c")) )
		{
			content += "compiling:";
		}
//		if( boost::regex_search(text,what, boost::regex("bc_cxx")) )
//		{
//			content += "compiling:";
//		}
		if( boost::regex_search(text,what, boost::regex("bc_link")) )
		{
			content += "collctiong:";
			output = true;
		}
		if( boost::regex_search(text,what, boost::regex("llc")) )
		{
			content += "converting:";
			output = true;
		}
		if( boost::regex_search(text,what, boost::regex("as")) )
		{
			content += "assembling:";
			output = true;
		}
		if( boost::regex_search(text,what, boost::regex("ar")) )
		{
			content += "archieving:";
			output = true;
		}
		if( boost::regex_search(text,what, boost::regex("ld_")) )
		{
			content += "linking:";
			output = true;
		}
		if( boost::regex_search(text,what, boost::regex("rm_cmd")) )
		{
			content += "clean:";
			output = true;
		}
	}
	if( boost::regex_search(cmd,what, boost::regex("<input>(.*)</input>")) )
	{
		string text(what[0]);
		string tag("input");
		int length  = text.size() - 2*tag.size() -2 -3;
		content += text.substr(tag.size() +2, length);
	}
	if( output && boost::regex_search(cmd,what, boost::regex("<output>(.*)</output>")) )
	{
		string text(what[0]);
		string tag("output");
		int length  = text.size() - 2*tag.size() -2 -3;
		content += " " + text.substr(tag.size() +2, length);
	}
	if(content.empty())
	{
		return;
	}
	this->m_ViewInfo.push_back(content);
}
void InfoCollectMgr::parseReportResult(const string &log)
{
//	boost::regex rex("(<[^>]*>)");
	boost::smatch what;
	string logpath;
	if( boost::regex_search(log,what, boost::regex("<log>(.*)</log>") ))
	{
		string text(what[0]);
		string tag("log");
		int length  = text.size() - 2*tag.size() -2 -3;
		logpath = text.substr(tag.size() +2, length);
	}
//	ttcode_log << "logpath=<" << logpath << ">" << endl;
	if(logpath.empty())
	{
		return;
	}
	try
	{
		ifstream ifs ( logpath.c_str() , ifstream::in );
		while( ifs.good() && !ifs.eof() )
		{
			char linebuf[1024];
			memset(linebuf,0x0,sizeof(linebuf));
			ifs.getline(linebuf,sizeof(linebuf));
			string buf(linebuf);
			this->m_ViewInfo.push_back(string(linebuf));
		}
		ifs.close();
	}
	catch(...)
	{}
// parse tag
	string id;
	if( boost::regex_search(log,what, boost::regex("<tag>(.*)</tag>") ))
	{
		string text(what[0]);
		string tag("tag");
		int length  = text.size() - 2*tag.size() -2 -3;
		id = text.substr(tag.size() +2, length);
	}
	if( id.empty() )
	{
		return;
	}
	globalDocMgr->modifyLogInfo( id ,"build",logpath );
}


class ttProcess : public wxProcess
{
public:
    ttProcess()
    :wxProcess(wxPROCESS_REDIRECT)
    {
    }

    // instead of overriding this virtual function we might as well process the
    // event from it in the frame class - this might be more convenient in some
    // cases
    virtual void OnTerminate(int pid, int status)
	{}

protected:
};

void InfoCollectMgr::daemonApplicationNative(const std::string &name, const std::string &param)
{

	ttcode_log << "name=<" << name << ">" << endl;
	ttcode_log << "param=<" << param << ">" << endl;

	ttProcess *proc = new ttProcess();
	std::string program = name + " " + param;
	wxExecute(program.c_str(), wxEXEC_ASYNC, proc);
}

